1 module hip.api.data.audio; 2 3 import hip.api.audio; 4 public import hip.api.audio.audioclip; 5 6 enum HipAudioEncoding 7 { 8 WAV, 9 MP3, 10 OGG, 11 MIDI, //Probably won't support 12 FLAC, 13 MOD, 14 XM 15 } 16 17 HipAudioEncoding getEncodingFromName(string name) 18 { 19 int i = cast(int)name.length-1; 20 while(i >= 0 && name[i] != '.'){i--;} if(name[i] == '.') i++; 21 switch(name[i..$]) 22 { 23 case "wav":return HipAudioEncoding.WAV; 24 case "ogg":return HipAudioEncoding.OGG; 25 case "mp3":return HipAudioEncoding.MP3; 26 case "flac":return HipAudioEncoding.FLAC; 27 case "mod": return HipAudioEncoding.MOD; 28 case "xm": return HipAudioEncoding.XM; 29 case "mid": 30 case "midi":return HipAudioEncoding.MIDI; 31 default: assert(false, "Encoding from file '"~name~", is not supported."); 32 } 33 } 34 35 interface IHipAudioDecoder 36 { 37 bool decode(in ubyte[] data, HipAudioEncoding encoding, HipAudioType type, 38 void delegate(in ubyte[] data) onSuccess, void delegate() onFailure); 39 40 bool resample(in ubyte[] data, HipAudioType type, uint outputSampleRate, uint outputChannels, 41 void delegate(in ubyte[] data) onSuccess, void delegate() onFailure); 42 43 ///Channel conversion is a very simple implementation, so, I won't use delegates for it. 44 bool channelConversion(in ubyte[] data, ubyte from, ubyte to); 45 /** 46 * Receives the raw data. Deals with the data based on clip hint. 47 */ 48 final bool loadData(in ubyte[] data, HipAudioEncoding encoding, HipAudioType type, HipAudioClipHint hint, 49 void delegate(in ubyte[] data) onSuccess, void delegate() onFailure) 50 { 51 if(data.length == 0) 52 { 53 onFailure(); 54 return false; 55 } 56 57 if(hint.needsDecode) 58 { 59 decode(data, encoding, type, (in ubyte[] decodedData) 60 { 61 if(hint.needsResample && getSamplerate != hint.outputSamplerate) 62 { 63 resample(decodedData, type, hint.outputSamplerate, hint.outputChannels, (in ubyte[] resampledData) 64 { 65 if(hint.needsChannelConversion && getClipChannels != hint.outputChannels && 66 !channelConversion(resampledData, getClipChannels, cast(ubyte)hint.outputChannels)) 67 { 68 onFailure(); 69 return; 70 } 71 onSuccess(getClipData); 72 }, onFailure); 73 } 74 else 75 onSuccess(decodedData); 76 }, onFailure); 77 } 78 else if(hint.needsResample && getSamplerate != hint.outputSamplerate) 79 { 80 resample(getClipData, type, hint.outputSamplerate, hint.outputChannels, (in ubyte[] resampledData) 81 { 82 if(hint.needsChannelConversion && getClipChannels != hint.outputChannels && 83 !channelConversion(resampledData, getClipChannels, cast(ubyte)hint.outputChannels)) 84 onFailure(); 85 onSuccess(getClipData); 86 }, onFailure); 87 } 88 else if(hint.needsChannelConversion && getClipChannels != hint.outputChannels) 89 { 90 channelConversion(getClipData, getClipChannels, cast(ubyte)hint.outputChannels); 91 onSuccess(getClipData); 92 } 93 94 return true; 95 } 96 ///Used for streaming. 97 uint startDecoding(in ubyte[] data, ubyte[] outputDecodedData, uint chunkSize, HipAudioEncoding encoding) 98 in (chunkSize > 0 , "Chunk size must be greater than 0"); 99 uint updateDecoding(ubyte[] outputDecodedData); 100 AudioConfig getAudioConfig(); 101 ubyte[] getClipData(); 102 ubyte getClipChannels(); 103 size_t getClipSize(); 104 ///Don't apply to streamed audio. Gets the duration in seconds 105 float getDuration(); 106 107 void dispose(); 108 uint getSamplerate(); 109 110 } 111 112 enum AudioFormat : ushort 113 { 114 signed8, 115 signed16Little, 116 signed16Big, 117 signed32Little, 118 signed32Big, 119 unsigned8, 120 unsigned16Little, 121 unsigned16Big, 122 float32Little, 123 float32Big, 124 _default = signed16Little 125 } 126 127 enum audioConfigDefaultBufferSize = 4096; 128 129 130 struct AudioConfig 131 { 132 int sampleRate; 133 AudioFormat format; 134 uint channels; 135 int bufferSize; 136 137 static enum defaultBufferSize = audioConfigDefaultBufferSize; 138 139 140 141 /** 142 * Returns a default audio configuration for 2D 143 */ 144 static AudioConfig musicConfig() 145 { 146 return AudioConfig(44_100, AudioFormat.float32Little, 2, audioConfigDefaultBufferSize); 147 } 148 static AudioConfig androidConfig() 149 { 150 return AudioConfig(22_050, AudioFormat.float32Little, 1U, 2048); 151 } 152 static AudioConfig lightweightConfig() 153 { 154 return AudioConfig(22_050, AudioFormat._default, 1U, 2048); 155 } 156 157 uint getBitDepth() 158 { 159 switch(format) with(AudioFormat) 160 { 161 case signed8: 162 case unsigned8: 163 return 8; 164 case signed16Big: 165 case signed16Little: 166 case unsigned16Big: 167 case unsigned16Little: 168 return 16; 169 case signed32Big: 170 case signed32Little: 171 case float32Big: 172 case float32Little: 173 return 32; 174 default:return 0; 175 } 176 } 177 }